package com.stone.serverless.core.classloader.config;

import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import com.stone.serverless.sdk.event.ComponentConsumer;
import com.stone.serverless.sdk.event.ComponentProvider;
import com.stone.serverless.sdk.event.ComponentRefresh;
import com.stone.serverless.sdk.event.ComponentRunner;
import com.stone.serverless.sdk.handler.ComponentInvocationAfterHandler;
import com.stone.serverless.sdk.handler.ComponentInvocationBeforeHandler;
import com.stone.serverless.sdk.loader.ModuleClassLoader;
import com.stone.serverless.sdk.rumtime.ContainerRuntime;
import lombok.Getter;
import lombok.Setter;
import lombok.SneakyThrows;

import java.util.Map;

/**
 * @Description: TODO
 * @Author: MECHREVO
 * @Date: 2022/1/17 16:52
 * @Version: 1.0.0
 */
@Getter
@Setter
public class ComponentEnvironmentConfig {
    private Map<String, Object> environment;

    private Object componentProvider;

    private Object componentConsumer;

    private Object componentRunner;

    private Object componentRefresh;

    private ContainerRuntime containerRuntime;

    private Object beforeHandler;

    private Object afterHandler;

    public ComponentEnvironmentConfig(Map<String, Object> environment) {
        this.environment = environment;
    }

    public <T> T getEnvironment(String key) {
        return (T) this.environment.get(key);
    }


    public void setComponentProvider(Object componentProvider) {
        this.componentProvider = componentProvider;
        this.setInstance(this.componentProvider);
    }


    public void setComponentConsumer(Object componentConsumer) {
        this.componentConsumer = componentConsumer;
        this.setInstance(this.componentConsumer);
    }

    public void setInstance(Object objBean) {
        this.setInstance(objBean, objBean);
    }

    public void setInstance(Object objBean, Object value) {
        if (ReflectUtil.hasField(objBean.getClass(), "INSTANCE")) {
            ReflectUtil.setFieldValue(objBean.getClass(), "INSTANCE", value);
        }
    }

    public void setComponentRunner(Object componentRunner) {
        this.componentRunner = componentRunner;
        this.setInstance(this.componentRunner);
    }

    public void setBeforeHandler(Object beforeHandler) {
        this.beforeHandler = beforeHandler;
        this.setInstance(beforeHandler);
    }

    public void setAfterHandler(Object afterHandler) {
        this.afterHandler = afterHandler;
        this.setInstance(afterHandler);
    }

    public void setComponentRefresh(Object componentRefresh) {
        this.componentRefresh = componentRefresh;
        this.setInstance(this.componentRefresh);
    }

    public void uninstallCprr(Object... beans) {
        for (Object bean : beans) {
            if (bean != null) {
                setInstance(bean, null);
            }
        }

    }


    @SneakyThrows
    public void loadComponentProvider(Class<?> loadClass, ModuleClassLoader moduleClassLoader) {
        if (ObjectUtil.isNull(loadClass)) {
            return;
        }
        Class<?> aClass = moduleClassLoader.loadClass(ComponentProvider.class.getName());
        //获取父类
        if (!loadClass.getName().equals(aClass.getName())&&ClassUtil.isAssignable(aClass,loadClass)) {
            //实例化
            Object obj = loadClass.newInstance();
            this.setComponentProvider(obj);
        }
    }


    @SneakyThrows
    public void loadComponentConsumer(Class<?> loadClass, ModuleClassLoader moduleClassLoader) {
        if (ObjectUtil.isNull(loadClass)) {
            return;
        }
        Class<?> aClass = moduleClassLoader.loadClass(ComponentConsumer.class.getName());
        //获取父类
        if (!loadClass.getName().equals(aClass.getName())&&ClassUtil.isAssignable(aClass,loadClass)) {
            //实例化
            Object obj = loadClass.newInstance();
            this.setComponentConsumer(obj);
        }
    }


    @SneakyThrows
    public void loadComponentRunner(Class<?> loadClass, ModuleClassLoader moduleClassLoader) {
        if (ObjectUtil.isNull(loadClass)) {
            return;
        }
        Class<?> aClass = moduleClassLoader.loadClass(ComponentRunner.class.getName());
        //获取父类
        if (!loadClass.getName().equals(aClass.getName())&&ClassUtil.isAssignable(aClass,loadClass)) {
            Object obj = loadClass.newInstance();
            this.setComponentRunner(obj);
        }

    }

    @SneakyThrows
    public void loadComponentInvocationBeforeHandler(Class<?> loadClass, ModuleClassLoader moduleClassLoader) {
        if (ObjectUtil.isNull(loadClass)) {
            return;
        }
        //获取父类
        Class<?> aClass = moduleClassLoader.loadClass(ComponentInvocationBeforeHandler.class.getName());
        if (!loadClass.getName().equals(aClass.getName())&&ClassUtil.isAssignable(aClass,loadClass)) {
            Object obj = loadClass.newInstance();
            this.setBeforeHandler(obj);
        }
    }


    @SneakyThrows
    public void loadComponentInvocationAfterHandler(Class<?> loadClass, ModuleClassLoader moduleClassLoader) {
        if (ObjectUtil.isNull(loadClass)) {
            return;
        }
        //获取父类
        Class<?> aClass = moduleClassLoader.loadClass(ComponentInvocationAfterHandler.class.getName());
        if (!loadClass.getName().equals(aClass.getName())&&ClassUtil.isAssignable(aClass,loadClass)) {
            Object obj = loadClass.newInstance();
            this.setAfterHandler(obj);
        }
    }

    @SneakyThrows
    public void loadComponentRefresh(Class<?> loadClass, ModuleClassLoader moduleClassLoader) {
        if (ObjectUtil.isNull(loadClass)) {
            return;
        }

        //获取父类
        Class<?> aClass = moduleClassLoader.loadClass(ComponentRefresh.class.getName());
        if (!loadClass.getName().equals(aClass.getName())&&ClassUtil.isAssignable(aClass,loadClass)) {
            Object obj = loadClass.newInstance();
            this.setComponentRefresh(obj);
        }
    }

    public void uninstall() {
        this.environment = null;
        uninstallCprr(this.componentProvider,
                this.componentConsumer, this.componentRefresh,
                this.componentRunner, this.afterHandler,
                this.beforeHandler);
        if (null != this.componentRunner) {
            //this.componentRunner.stop();
            ReflectUtil.invoke(this.componentRunner, "stop");
        }
        if (null != containerRuntime) {
            this.containerRuntime.uninstall();
        }
        this.containerRuntime = null;
        this.componentProvider = null;
        this.componentConsumer = null;
        this.componentRefresh = null;
        this.componentRunner = null;
        this.afterHandler = null;
        this.beforeHandler = null;
    }
}
